package user

import (
	"context"
	"strconv"
	"strings"
	"time"

	"system-admin/config/mysql"
	"system-admin/config/redis"
	"system-admin/internal/define"
	"system-admin/internal/models"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"github.com/mojocn/base64Captcha"
)

// Login 登录
func Login(username, passwd string) (token string, err error) {
	db := mysql.NewDB()

	// 参数合法性检查
	if strings.TrimSpace(username) == "" {
		return "", errorx.New("用户名不能为空", -1)
	}
	if strings.TrimSpace(passwd) == "" {
		return "", errorx.New("密码不能为空", -1)
	}

	// 账号密码验证
	var user models.User
	{
		// 检查用户名或密码是否正确
		rowsAffected := db.Model(&models.User{}).
			Where(&models.User{
				Username: username,
				Password: generateEncryptPasswd(passwd),
			}).
			Take(&user).
			RowsAffected
		if rowsAffected <= 0 {
			return "", errorx.New("用户名或密码不正确", -1)
		}
		if user.Status == 2 {
			return "", errorx.New("该用户已被禁用", -1)
		}
	}

	// 获取用户的商户信息
	var merchant models.Merchant
	{
		db.Model(&models.Merchant{}).Where("id = ?", user.MerchantID).Take(&merchant)
	}

	// 生成token
	token = helper.Md5(strconv.Itoa(int(time.Now().UnixNano())) + helper.RandString(32))

	// 将token关联信息保存至redis
	rdb := redis.NewDB()
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
	defer cancel()
	_, err = rdb.HMSet(ctx, define.RedisUserLoginToken+token,
		"user_id", user.ID,
		"role_id", user.RoleID,
		"username", user.Username,
		"merchant_id", user.MerchantID,
		"merchant_name", merchant.Name,
		"merchant_path", merchant.MerchantPath,
	).Result()
	if err != nil {
		return "", nil
	}
	// 设置token的过期时间-2小时
	rdb.Expire(ctx, define.RedisUserLoginToken+token, time.Hour*2)

	// 更新最近一次登录时间
	db.Model(&models.User{}).Where("id = ?", user.ID).Update("latest_login", time.Now().Unix())

	// 返回token
	return token, nil
}

// LoginForDevice 设备端登录
func LoginForDevice(username, passwd string) (userID string, err error) {
	db := mysql.NewDB()

	// 参数合法性检查
	if strings.TrimSpace(username) == "" {
		return "", errorx.New("用户名不能为空", -1)
	}
	if strings.TrimSpace(passwd) == "" {
		return "", errorx.New("密码不能为空", -1)
	}

	// 账号密码验证
	var user models.User
	{
		// 检查用户名或密码是否正确
		rowsAffected := db.Model(&models.User{}).
			Where(&models.User{
				Username: username,
				Password: generateEncryptPasswd(passwd),
			}).
			Take(&user).
			RowsAffected
		if rowsAffected <= 0 {
			return "", errorx.New("用户名或密码不正确", -1)
		}
		if user.Status == 2 {
			return "", errorx.New("该用户已被禁用", -1)
		}
	}
	return user.ID, nil
}

// Login 登录
func LoginV2(username, passwd, captchaID, captchaCode string) (token string, err error) {
	db := mysql.NewDB()

	// 参数合法性检查
	if strings.TrimSpace(username) == "" {
		return "", errorx.New("用户名不能为空", -1)
	}
	if strings.TrimSpace(passwd) == "" {
		return "", errorx.New("密码不能为空", -1)
	}

	if err := ValidateCaptcha(captchaID, captchaCode); err != nil {
		return "", err
	}

	// 账号密码验证
	var user models.User
	{
		// 检查用户名或密码是否正确
		rowsAffected := db.Model(&models.User{}).
			Where(&models.User{
				Username: username,
				Password: generateEncryptPasswd(passwd),
			}).
			Take(&user).
			RowsAffected
		if rowsAffected <= 0 {
			return "", errorx.New("用户名或密码不正确", -1)
		}
		if user.Status == 2 {
			return "", errorx.New("该用户已被禁用", -1)
		}
	}

	// 获取用户的商户信息
	var merchant models.Merchant
	{
		db.Model(&models.Merchant{}).Where("id = ?", user.MerchantID).Take(&merchant)
	}

	// 生成token
	token = helper.Md5(strconv.Itoa(int(time.Now().UnixNano())) + helper.RandString(32))

	// 将token关联信息保存至redis
	rdb := redis.NewDB()
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
	defer cancel()
	_, err = rdb.HMSet(ctx, define.RedisUserLoginToken+token,
		"user_id", user.ID,
		"role_id", user.RoleID,
		"username", user.Username,
		"merchant_id", user.MerchantID,
		"merchant_name", merchant.Name,
		"merchant_path", merchant.MerchantPath,
	).Result()
	if err != nil {
		return "", nil
	}
	// 设置token的过期时间-2小时
	rdb.Expire(ctx, define.RedisUserLoginToken+token, time.Hour*2)

	// 更新最近一次登录时间
	db.Model(&models.User{}).Where("id = ?", user.ID).Update("latest_login", time.Now().Unix())

	// 返回token
	return token, nil
}

type Captcha struct {
	CaptchaID  string `json:"captcha_id"`
	CaptchaImg string `json:"captcha_img"`
}

func GetCaptcha() (*Captcha, error) {
	// 验证码数字
	digits := base64Captcha.NewDriverDigit(80, 240, 5, 0.7, 80)
	// 生成base64图片
	store := base64Captcha.DefaultMemStore
	c := base64Captcha.NewCaptcha(digits, store)
	id, base64Img, _, err := c.Generate()
	if err != nil {
		return nil, errorx.New("生成验证码失败", -1)
	}
	rdb := redis.NewDB()
	rdb.Set(context.Background(), define.RedisCaptcha+id, store.Get(id, false), time.Minute) // 缓存验证码内容至redis
	var captcha Captcha
	captcha.CaptchaID = id
	captcha.CaptchaImg = base64Img
	return &captcha, nil
}

// ValidateCaptcha 验证图形验证码
func ValidateCaptcha(captchaID string, captchaCode string) error {
	rdb := redis.NewDB()
	val, _ := rdb.Get(context.Background(), define.RedisCaptcha+captchaID).Result()
	if val != captchaCode {
		return errorx.New("无效的验证码", -1)
	}
	return nil
}

// Logout 登出
func Logout(token string) error {
	rdb := redis.NewDB()
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
	defer cancel()
	rdb.Del(ctx, define.RedisUserLoginToken+token).Result()
	return nil
}
